

// NovitasIRCd
// Created by Thomas David Dalladay (Uzelth)
// File: server.c

// ##########################################
// #          START BUILD SETTINGS          #
// ##########################################

// Enable if MagaIRCd keeps crashing.
#define MAINTENANCEMODE 0

// Enable or disable flood protection.
#define FLOODPROTECT 1

// Time (in seconds ) to PING the client.
#define PINGSECONDS 90

// Time to disconnect inactive/unresponsive connections.
#define PINGTIMEOUT 60

// Number of connections permitted per IP.
#define CONNECTIONSPERIP 25

// Maximum number of channels a user can join.
#define MAXCHANSPERUSER 15

// Maximum number of users per users.
#define MAXUSERS 300

// If you want to use epoll(), enable this.
#define USEEPOLL

// Compress data (several lines to the send buffer simultaneously).
#define SENDCOMPRESSED 1

// ########################################
// #          END BUILD SETTINGS          #
// ########################################



// ###################################################
// # !!!! DO NOT EDIT ANYTHING AFTER THIS BLOCK !!!! #
// ###################################################

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <signal.h>
#include <errno.h>
#ifdef USEEPOLL
#include <sys/epoll.h>
#endif

char ServerVersion[50] = "0.0.1";
char MD5Result[5000];

#include "md5.c"
#define BUF 512
#define MAXBANSPERCHAN 20
#define SENDBUFFERSIZE 2000
#define RECVLENGTH 2048
#define PROCESSLENGTH 2048
#define SENDBUFFERITEM 800
#define MAXCHANNELS 300
#define MAXINVITESPERCHAN 20

#define MOTDLINES 500
#define MOTDLINELEN 300

#define MAXUSERMASKLEN 200

#define MAXKILLSATONCE 100

#define CHANPWLEN 30

#define MAX_EPOLL_EVENTS_PER_RUN 20
#define EPOLL_RUN_TIMEOUT 50
#define EPOLL_QUEUE_LEN 50

#ifndef false
#define false 0
#endif
#ifndef true
#define true (! false)
#endif

typedef char bool;

extern int ErrNo;
bool BigDebug;

int MaxUsers = 1;
int MOTDLines;
int ServicesSocket;
int LastSendClientNR;
int ClientInvitePoints[MAXUSERS];
int ClientInChannel[MAXUSERS][MAXCHANSPERUSER];
int ClientFloodPoints[MAXUSERS];
int ClientWhoChannels[MAXUSERS];
int ClientSockets[MAXUSERS];
long LastGLineSave = 0;
long LastUserDebug;
long ServicesLastSaidTime;
long ClientPleaseRemoveTime[MAXUSERS];
long ClientRegistrationTime[MAXUSERS];
long ClientLastMOTD[MAXUSERS];
long ClientLastLIST[MAXUSERS];
long ClientLastINFO[MAXUSERS];
long ClientLastLUSERS[MAXUSERS];
long ClientLastFloodMinus[MAXUSERS];
long ClientLastSaid[MAXUSERS];
long ClientLastPING[MAXUSERS];
bool FilterColours;
bool ConfFilterColours;
bool ServicesConnected;
bool ClientExists[MAXUSERS];
bool ClientPleaseRemove[MAXUSERS];
bool ClientPleaseRemoveQuitMessageSent[MAXUSERS];
bool ClientSendStuffBeforeRemove[MAXUSERS];
bool ClientIRCOperator[MAXUSERS];
bool ClientCloseSocket[MAXUSERS];
bool ClientErrorReason[MAXUSERS][300];
bool ClientAuthed[MAXUSERS];
bool ClientInChannelAdmin[MAXUSERS][MAXCHANSPERUSER];
bool ClientInChannelOp[MAXUSERS][MAXCHANSPERUSER];
bool ClientInChannelHOp[MAXUSERS][MAXCHANSPERUSER];
bool ClientInChannelVoice[MAXUSERS][MAXCHANSPERUSER];
bool ClientCancelJoining[MAXUSERS];
bool ClientServicesValueSent[MAXUSERS];
char FirstBindValue[20];
char GETNICKCHAR[PROCESSLENGTH];
char MOTD[MOTDLINES][MOTDLINELEN];
char BindIP[50] = "";
char ServerName[50];
char NetworkName[50];
char ServicesHost[50];
char ServicesPwd[50];
char ServicesIP[50];
char ConfServerName[50];
char ConfNetworkName[50];
char ConfServicesHost[50];
char ConfServicesPwd[50];
char ConfServicesIP[50];
char ServicesReceiptString[RECVLENGTH];
char ServicesSendString[1000][SENDBUFFERITEM];
char ReceiptString[MAXUSERS][RECVLENGTH];
char SendString[MAXUSERS][SENDBUFFERSIZE][SENDBUFFERITEM];
char ClientIP[MAXUSERS][300];
char ClientAwayReason[MAXUSERS][210];
char ClientNickname[MAXUSERS][30];
char ClientRealname[MAXUSERS][51];
char ClientUserID[MAXUSERS][15];
char ClientHost[MAXUSERS][60];
char ClientAuthPongValue[MAXUSERS][60];
char ClientTimeoutPingValue[MAXUSERS][100];
char ClientServicesValue[MAXUSERS][100];

// User modes.
bool ClientModeWallUser[MAXUSERS];
bool ClientModeInvisible[MAXUSERS];

int ChannelUserLimit[MAXCHANNELS];
int ChannelInvite[MAXCHANNELS][MAXINVITESPERCHAN];
int ConfRehash;
long ChannelTopicSetTime[MAXCHANNELS];
long ChannelCreationTime[MAXCHANNELS];
long ChannelBansTime[MAXCHANNELS][MAXBANSPERCHAN];
long ChannelInviteTime[MAXCHANNELS][MAXINVITESPERCHAN];
bool ChannelExists[MAXCHANNELS];
bool ChannelModeTegistered[MAXCHANNELS];
bool ChannelModeOnlyOpsTopic[MAXCHANNELS];
bool ChannelModeAutoVoice[MAXCHANNELS];
bool ChannelModeModerated[MAXCHANNELS];
bool ChannelModePrivate[MAXCHANNELS];
bool ChannelModeBlockColours[MAXCHANNELS];
bool ChannelModeInviteOnly[MAXCHANNELS];
bool ChannelModeIRCOpsOnly[MAXCHANNELS];
char ProcessString[PROCESSLENGTH];
char ChannelName[MAXCHANNELS][25];
char ChannelTopic[MAXCHANNELS][205];
char ChannelTopicSetBy[MAXCHANNELS][50];
char ChannelPwd[MAXCHANNELS][CHANPWLEN + 1];
char ChannelBansActor[MAXCHANNELS][MAXBANSPERCHAN][50];
char PValue[6];
char ConfigPath[PROCESSLENGTH];
char CValue[8];
char ConfCValue[8];
char ConfPValue[8];

unsigned int NumCount = 0;
unsigned char ChannelBans[MAXCHANNELS][MAXBANSPERCHAN][MAXUSERMASKLEN];

int ClearEmptyChans() {
	int R;
	R = 0;

	while(R < MAXCHANNELS) {
		if (ChannelExists[R] == true) {
			if (ChannelModeRegistered[R] == false) {
				if (ChannelUserCount(R) <= 0) {
					ChannelExists[R] = false;
				}
			}
		}

		R += 1;
	}
}

#include "Strings.c"
#include "Masks.c"
#include "ChannelForwardings.c"
#include "ParseConf.c"
#include "Sockets.c"
#include "GLines.c"

void GetServicesValue(int NR) {
	NumCount += 1;

	if(NumCount >= 10000000) {
		NumCount -= 10000000;
	}

	sprintf(&MyStringLeReplace[0],"blablu%dbla%d-%d",NumCount + 1,(unsigned)time(NULL),(unsigned)time(NULL));
	MDString(MyStringLeReplace);
	sprintf(&MyStringLeReplace[0],"%shuhuhuhu%d-%d",MD5Result,NumCount,(unsigned)time(NULL));
	MDString(MyStringLeReplace);
	strcpy(ClientServicesValue[NR],MD5Result);
}

void GetPwdVal(char* ServicesVal,char* Pww) {
	sprintf(&MyStringLeReplace[0],"%s%shallo1343§%§$",ServicesVal,Pwd);
	MDString(MyStringLeReplace);
	strcpy(MyStringLeReplace,MD5Result);
}

int GetChannelModes(int ChanID,bool Outside) {
	char TempStr[PROCESSLENGTH];
	strcpy(MyStringLeReplace,"n");

	if(ChannelModeBlockColours[ChanID] == true) {
		strcat(MyStringLeReplace,"c");
	}

	if(ChannelModeModerated[ChanID] == true) {
		strcat(mystringle_replace,"m");
	}

	if(ChannelModePrivate[ChanID] == true) {
		strcat(MyStringLeReplace,"s");
	}

	if(ChannelModeOnlyOpsTopic[ChanID] == true) {
		strcat(MyStringLeReplace,"t");
	}

	if(ChannelModeRegistered[ChanID] == true) {
		strcat(MyStringLeReplace,"r");
	}

	if(ChannelModeInviteOnly[ChanID] == true) {
		strcat(MyStringLeReplace,"i");
	}

	if(ChannelUserLimit[ChanID] > 0) {
		strcat(MyStringLeReplace,"l");
	}

	if(strcasecmp(ChannelPwd[ChanID],"") != 0) {
		strcat(MyStringLeReplace,"k");
	}

	if(ChannelUserLimit[ChanID] > 0 && Outside == false) {
		sprintf(&TempStr[0]," %d",ChannelUserLimit[ChanID]);
		strcat(MyStringLeReplace,TempStr);
	}

	if(strcasecmp(ChannelPwd[ChanID],"") != 0 && Outside == false) {
		strcat(MyStringLeReplace," ");
		strcat(MyStringLeReplace,ChannelPwd[ChanID]);
	}
}

int ChanNumber(char* VChannelName) {
	int R;
	R = 0;

	while(R < MAXCHANNELS) {
		if(strcasecmp(ChannelName[R],VChannelName) == 0 && ChannelExists[R] == true) {
			return R;
		}

		R += 1;
	}

	return -1;
}

int OpenChannel(char* VChannelName) {
	char LocalString[PROCESSLENGTH];

	strncpy(LocalString,VChannelName,PROCESSLENGTH - 2);
	LocalString[PROCESSLENGTH - 2] = 0;

	int K;

	K = ChanNumber(VChannelName);

	if(K >= 0) {
		return K;
	}

	int R;
	R = 0;

	while(R < MAXCHANNELS) {
		if(ChannelExists[R] == false) {
			ChannelExists[R] = true;
			strcpy(LocalString,VChannelName);
			strlwr(LocalString);
			sprintf(&ChannelName[R][0],"%s",LocalString);
			//strcpy(ChannelName[R],VChannelName);
			strcpy(ChannelTopic[R],"");
			strcpy(ChannelTopicSetBy[R],"");
			ChannelTopicSetTime[R] = 0;
			ChannelModeRegistered[R] = false;
			ChannelModeOnlyOpsTopic[R] = false;
			ChannelModeAutoVoice[R] = false;
			ChannelModeModerated[R] = false;
			ChannelModePrivate[R] = false;
			ChannelModeBlockColours[R] = false;
			ChannelModeInviteOnly[R] = false;
			ChannelCreationTime[R] = time(NULL);
			ChannelUserLimit[R] = 0;
			strcpy(ChannelPwd[R],"");

			K = 0;

			while(K < MAXBANSPERCHAN) {
				strcpy(ChannelBans[R][K],"");
				ChannelBansTime[R][K] = 0;
				K += 1;
			}

			K = 0;

			while(K < MAXINVITESPERCHAN) {
				ChannelInvite[R][K] = -1;
				ChannelInviteTime[R][K] = 0;
				K += 1;
			}

			return R;
		}

		R += 1;
	}

	return -1;
}

void RemoveExpiredInvites() {
	int R = 0;
	int K = 0;

	while(R < MAXCHANNELS) {
		K = 0;

		while(K < MAXINVITESPERCHAN) {
			if(ChannelInvite[R][K] >= 0) {
				if(ClientExists[ChannelInvite[R][K]] == false || 
				ClientPleaseRemove[ChannelInvite[R][K]] == true || 
				ClientAuthed[ChannelInvite[R][K]] == false || 
				ChannelInviteTime[R][K] + (60 * 60 * 2) < time(NULL)) {
					ChannelInvite[R][K] = -1;
				}
			}
			K += 1;
		}
		R += 1;
	}
}

bool UserIsInvited(int ChanID,int ClientID) {
	RemoveExpiredInvites();

	int R = 0;

	while(R < MAXCHANNELS) {
		if(ChannelInvite[ChanID][R] == ClientID) {
			return true;
		}

		R += 1;
	}
	return false;
}

void ClearInvite(int ChanID,int ClientID) {
	RemoveExpiredInvites();

	int R = 0;

	while(R < MAXCHANNELS) {
		if(ChannelInvite[ChanID][R] == ClientID) {
			ChannelInvite[ChanID][R] = -1;
		}

		R += 1;
	}
}

void AddInvite(int ChanID,int ClientID) {
	RemoveExpiredInvites();

	int R = 0;

	while(R < MAXCHANNELS) {
		if(ChannelInvite[ChanID][R] < 0) {
			ChannelInvite[ChanID][R] = ClientID;
			ChannelInviteTime[ChanID][R] = time(NULL);
			return;
		}

		R += 1;
	}
}

bool ChannelFree(int UserID) {
	int R;
	R = 0;

	while(R < MAXCHANSPERUSER) {
		if(ClientInChannel[UserID][R] < 0) {
			return true;
		}

		R += 1;
	}

	return false;
}

bool UserIsInChannel(int UserID,int ChannelID) {
	if(ClientExists[UserID] == false || ClientPleaseRemove[UserID] == true) {
		return false;
	}

	int R;
	R = 0;

	while(R < MAXCHANSPERUSER) {
		if(ClientInChannel[UserID][R] == ChannelID) {
			return true;
		}
		R += 1;
	}
	return false;
}

int SendToAllUsersInChannel(int ChannelID,char* Stuff,int IgnoreUser) {
	int R;
	R = 0;

	while(R < MAXUSERS) {
		if(ClientExists[R] == true && ClientPleaseRemove[R] == false) {
			if(UserIsInChannel(R,ChannelID) == true && R != IgnoreUser) {
				VSend(Stuff,R);
			}
		}
		R += 1;
	}
}

int SendToAllRelatedUsers(int SourceUserID,char* Stuff) {
	if(ClientAuthed[SourceUserID] == false) {
		return;
	}

	bool UserIsIndicated[MAXUSERS];

	int R;
	R = 0;

	while(R < MAXUSERS) {
		UserIsIndicated[R] = false;
		R += 1;
	}

	R = 0;
	int K;
	K = 0;

	while(R < MAXCHANSPERUSER) {
		if(ClientInChannel[SourceUserID][R] >= 0) {
			K = 0;
			while(K < MAXUSERS) {
				if(ClientExists[K] == true && ClientPleaseRemove[K] == false && K != SourceUserID) {
					if(UserIsInChannel(K,ClientInChannel[SourceUserID][R]) == true) {
						SserIsIndicated[K] = true;
					}
				}

				K += 1;
			}
		}

		R += 1;
	}

	R = 0;

	while(R < MAXUSERS) {
		if(UserIsIndicated[R] == true) {
			VSend(Stuff,R);
		}

		R += 1;
	}
}

int UserAddChan(int UserID,int ChanID,char IsOp) {
	int R;
	R = 0;

	while(R < MAXCHANSPERUSER) {
		if(ClientInChannel[UserID][R] < 0) {
			ClientInChannel[UserID][R] = chanid;
			ClientInChannelOp[UserID][R] = false;
			ClientInChannelHOp[UserID][R] = false;
			ClientInChannelVoice[UserID][R] = false;
			if(MAINTENANCEMODE == 0) {
				ClientInChannelAdmin[UserID][R] = IsOp;
			} else {
				ClientInChannelAdmin[UserID][R] = false;
			}

			return;
		}

		R += 1;
	}
}

char* GetNick(int UserID) {
	strcpy(GETNICKCHAR,"");

	if(strcmp(ClientNickname[UserID],"") != 0) {
		strcpy(GETNICKCHAR,ClientNickname[UserID]);
		return GETNICKCHAR;
	} else {
		strcpy(GETNICKCHAR,"AUTH");
		return GETNICKCHAR;
	}
}

int ChannelUserCount(int Chan) {
	int R;
	R = 0;
	int K;
	K = 0;

	while(R < MAXUSERS) {
		if(ClientExists[R] == true && ClientPleaseRemove[R] == false) {
			if(UserIsInChannel(R,Chan) == true) {
				K += 1;
			}
		}

		R += 1;
	}
	return K;
}

#include "Mode.c"
#include "Startup.c"
#include "Logging.c"

char VUserList[PROCESSLENGTH];

int UserList(int ChanID) {
	strcpy(VUserList,"");

	int R;
	int K;
	R = 0;

	while(R < MAXUSERS) {
		if(ClientExists[R] == true && ClientPleaseRemove[R] == false) {
			K = 0;
			while(K < MAXCHANSPERUSER) {
				if(ClientInChannel[R][K] == ChanID) {
					if(strcasecmp(VUserList,"") != 0) {
						strcat(VUserList," ");
					}

					if(ClientInChannelAdmin[R][K] == true) {
						strcat(VUserList,"&");
					} else {
						if(ClientInChannelOp[R][K] == true) {
							strcat(VUserList,"@");
						} else {
							if(ClientInChannelHop[R][K] == true) {
								strcat(VUserList,"%");
							} else {
								if(ClientInChannelVoice[R][K] == true) {
									strcat(VUserList,"+");
								}
							}
						}
					}

					strcat(VUserList,GetNick(R));
				}

				K += 1;
			}
		}

		R += 1;
	}

	if(ChannelModeRegistered[ChanID] == true) {
		if(strcasecmp(VUserList,"") != 0) {
			strcat(VUserList," ");
		}

		strcat(VUserList,"&");
		strcat(VUserList,GiveSVName("Chanserv"));
	}
}

int ChannelUserCount(int ChannelID) {
	int R;
	R = 0;
	int K;
	K = 0;
	int Z;
	Z = 0;

	while(R < MAXUSERS) {
		if(ClientExists[R] == true && ClientPleaseRemove[R] == false) {
			K = 0;

			while(K < MAXCHANSPERUSER) {
				if(ClientInChannel[R][K] == ChannelID) {
					Z += 1;
				}

				K += 1;
			}
		}

		R += 1;
	}

	if(ChannelModeRegistered[ChannelID] == true) {
		return Z + 1;
	}

	return Z;
}

int GiveUserID(char* Username) {
	int R;
	R = 0;

	while(R < MAXUSERS) {
		if(strcasecmp(ClientNickname[R],Username) == 0 && ClientAuthed[R] == true && ClientExists[R] == true && ClientPleaseRemove[R] == false) {
			return R;
		}

		R += 1;
	}

	return -1;
}

int ChannelID(char* ChanName) {
	if(FChannelExists(ChanName) == false) {
		return -1;
	}

	int R;
	R = 0;

	while(R < MAXCHANNELS) {
		if(strcasecmp(ChannelName[R],ChanName) == 0 && ChannelExists[R] == true) {
			return R;
		}

		R += 1;
	}
}

int SendChannelNames(int UserID,int ChanId) {
	UserList(ChanID);

	char MyBastel[PROCESSLENGTH];
	strcpy(MyBastel,"");

	char VUserlist[PROCESSLENGTH] = "";
	int R;
	R = 0;
	int K = 0;
	int UserListUserCount = 0;

	while(R < MAXUSERS) {
		if(ClientExists[R] == true && ClientPleaseRemove[R] == false) {
			K = 0;

			while(K < MAXCHANSPERUSER) {
				if(ClientInChannel[R][K] == ChanID) {
					if(strcasecmp(VUserList,"") != 0) {
						strcat(VUserList," ");
					}

					if(ClientInChannelAdmin[R][K] == true) {
						strcat(VUserList,"&");
					} else {
						if(ClientInChannelOp[R][K] == true) {
							strcat(VUserList,"@");
						} else {
							if(ClientInChannelHOp[R][K] == true) {
								strcat(VUserList,"%");
							} else {
								if(ClientInChannelVoice[R][K] == true) {
									strcat(VUserList,"+");
								}
							}
						}
					}

					strcat(VUserList,GetNick(R));
					UserListUserCount += 1;

					if(UserListUserCount >= 10) {
						sprintf(&MyBastel[0],"%s %s = %s :%s",ServerSubject(" 353"),GetNick(UserID),ChannelName[ChanID],VUserList);
						VSend(MyBastel,userID);
						strcpy(VUserlist,"");
						UserListUserCount = 0;
					}
				}

				K += 1;
			}
		}

		R += 1;
	}

	if(ChannelModeRegistered[ChanID] == true) {
		if(strcasecmp(VUserList,"") != 0) {
			strcat(VUserList," ");
		}

		strcat(VUserList,"&");
		strcat(VUserList,GiveSVName("Chanserv"));
	}

	sprintf(&MyBastel[0],"%s %s = %s :%s",ServerSubject(" 353"),GetNick(UserID),ChannelName[ChanID],VUserList);
	VSend(MyBastel,UserID);
	sprintf(&MyBastel[0],"%s %s %s :End of /NAMES list",ServerSubject(" 366"),GetNick(UserID),ChannelName[ChanID]);
	VSend(MyBastel,UserID);
}

char Bastel2Str[500];

int MoveUserInChannel(int UserID,char* Chan) {
	char BastelStr[PROCESSLENGTH];
	strcpy(BastelStr,"");

	if(ChannelFree(UserID) == false) {
		return -1;
	}

	int K;
	K = OpenChannel(Chan);

	if(UserIsInChannel(UserID,K) == false) {
		if(ChannelUserCount(K) > 0) {
			UserAddChan(UserID,K,0);
		} else {
			UserAddChan(UserID,K,1);
		}

		strcpy(Bastel2Str,ChannelName[K]);
		strlwr(Bastel2Str);
		sprintf(&BastelStr[0],":%s!%s@%s JOIN %s",GetNick(UserID),ClientUserID[UserID],ClientHost[UserID],Bastel2Str);
		SendToAllUsersInChannel(K,BastelStr,-1);

		if(MAINTENANCEMODE == 0) {
			if(ChannelTopicSetTime[K] > 0) {
				sprintf(&BastelStr[0],"%s %s %s :%s",ServerSubject(" 332"),GetNick(UserID),ChannelName[K],ChannelTopic[K]);
				VSend(BastelStr,UserID);
				sprintf(&BastelStr[0],"%s %s %s %s %d",ServerSubject(" 333"),GetNick(UserID),ChannelName[K],ChannelTopicSetBy[K],ChannelTopicSetTime[K]);
				vsend(bastelstr,userid);
			}
		} else {
			sprintf(&BastelStr[0],"%s %s %s :%s",ServerSubject(" 332"),GetNick(UserID),ChannelName[K],"MAINTENANCE MODE - this means there is some serious issue and the server can't run normally without crashing");
			Vsend(BastelStr,UserID);
		}

		SendChannelNames(UserID,K);
		GetChannelModes(K,false);
		sprintf(&BastelStr[0],"%s %s %s +%s",ServerSubject(" 324"),GetNick(UserID),ChannelName[K],MyStringLeReplace);
		VSend(BastelStr,UserID);
		sprintf(&BastelStr[0],"%s %s %s %d",ServerSubject(" 329"),GetNick(UserID),ChannelName[K],ChannelCreationTime[K]);
		VSend(BastelStr,UserID);

		return 0;
	}

	return 0;
}

bool NickNameInUse(char* Nick,int IgnoreClientID) {
	int FCount2;
	FCount2 = 0;

	while(FCount2 < MAXUSERS) {
		if(strcasecmp(ClientNickname[FCount2],Nick) == 0 
		&& ClientExists[FCount2] == true 
		&& ClientPleaseRemove[FCount2] == false 
		&& FCount2 != IgnoreClientID) {
			return true;
		}

		FCount2 += 1;
	}
	return false;
}

bool BannedOnChan(int ChannelID,int ClientID) {
	int R = 0;
	char Bla[PROCESSLENGTH];

	strcpy(Bla,ClientNickname[ClientID]);
	strcat(Bla,"!");
	strcat(Bla,ClientUserID[ClientID]);
	strcat(Bla,"@");
	strcat(Bla,ClientHost[ClientID]);

	while (R < MAXBANSPERCHAN) {
		if(strcasecmp(ChannelBans[ChannelID][R],"") != 0) {
			if(matches(Bla,ChannelBans[ChannelID][R]) == true) {
				// Banned.
				return true;
			}
		}

		R += 1;
	}

	return false;
}

bool UserIDValid(char* UserID) {
	if(strlen(UserID) < 1) {
		return false;
	}

	int FCount2;
	bool IsOkay;
	FCount2 = 0;

	while(FCount2 <= strlen(UserID) - 1) {
		IsOkay = false;

		// Uppercase.
		if(UserID[FCount2] >= 65 && UserID[FCount2] <= 90) {
			IsOkay = true;
		}

		// Lowercase.
		if(UserID[FCount2] >= 97 && UserID[FCount2] <= 122) {
			IsOkay = true;
		}

		// Numbers.
		if(UserID[FCount2] >= 48 && UserID[FCount2] <= 57) {
			IsOkay = true;
		}

		// Underscore (not at the beginning).
		if(UserID[FCount2] == 95 && FCount2 >= 1) {
			IsOkay = true;
		}

		if(IsOkay == false) {
			return false;
		}

		FCount2 += 1;
	}

	return true;
}

bool NicknameValid(char* Nick) {
	if(strlen(Nick) < 1) {
		return false;
	}

	int FCount2;
	int CharCount;
	CharCount = 0;
	bool IsOkay;
	FCount2 = 0;

	while(FCount2 <= strlen(Nick) - 1) {
		IsOkay = false;

		// Uppercase.
		if(Nick[FCount2] >= 65 && Nick[FCount2] <= 90) {
			IsOkay = true;
			CharCount += 1;
		}

		// Lowercase.
		if(Nick[FCount2] >= 97 && Nick[FCount2] <= 122) {
			IsOkay = true;
			CharCount += 1;
		}

		// Numbers (not at the beginning).
		if(Nick[FCount2] >= 48 && Nick[FCount2] <= 57 && FCount2 >= 1) {
			isokay = true;
		}

		// Special chars.
		if(Nick[FCount2] == '_' || Nick[FCount2] == '^' 
		|| Nick[FCount2] == '|' || Nick[FCount2] == '[' 
		|| Nick[FCount2] == ']' || Nick[FCount2] == '(' 
		|| Nick[FCount2] == ')' || Nick[FCount2] == '-') {
			IsOkay = true;
		}

		if(IsOkay == false) {
			return false;
		}

		FCount2 += 1;
	}

	if(CharCount <= 0) {
		return false;
	}

	return true;
}

// Long nicknames could cause a buffer overrun in the send message.
int CloseLongParameters(int ClientID) {
	ClientPleaseRemove[ClientID] = true;
	ClientPleaseRemoveTime[ClientID] = time(NULL);
	ClientSendStuffBeforeRemove[ClientID] = true;
	VSend("ERROR :You have been kicked for sending very long parameters where they are not needed (buffer overrun protection)",ClientID);
	strcpy(ClientErrorReason[ClientID],"Auto-killed for sending unbelievable long parameters (e.g. a 50 chars long nickname parameter)");
	ClearEmptyChans();
}

int CloseInvalidUserID(int ClientID) {
	ClientPleaseRemove[ClientID] = true;
	ClientPleaseRemoveTime[ClientID] = time(NULL);
	ClientSendStuffBeforeRemove[ClientID] = true;
	VSend("ERROR :Your userid is invalid. Please use only a-z A-Z and 0-9 and _ (not at the beginning)!",ClientID);
	strcpy(ClientErrorReason[ClientID],"Invalid userid");
	ClearEmptyChans();
}

char VSndStr[500];

int SendNumeric(int Num,int ClientNR,char* Content) {
	char SSTR[800];
	char TheNum[20];
	char TheNum2[20];
	int MaxLoops;
	sprintf(&TheNum[0],"%d",Num);
	MaxLoops = 0;

	while(strlen(TheNum) < 3 && MaxLoops < PROCESSLENGTH * 2) {
		strcpy(TheNum2,"0");
		strcat(TheNum2,TheNum);
		strcpy(TheNum,TheNum2);
		MaxLoops += 1;
	}

	strcpy(SSTR,"");
	strcpy(SSTR,ServerSsubject(" "));
	strcat(SSTR,TheNum);
	strcat(SSTR," ");
	strcat(SSTR,GetNick(ClientNR));
	strcat(SSTR," ");
	strcat(SSTR,Content);
	VSend(SSTR,ClientNR);
}

int UserCount() {
	int R;
	int K;

	R = 0;
	K = 0;
	while(R < MAXUSERS) {
		if(ClientExists[R] == true) {
			K += 1;
		}

		R += 1;
	}
	return K;
}

int OperCount() {
	int R;
	int K;
	R = 0;
	K = 0;
	while(R < MAXUSERS) {
		if(ClientExists[R] == true && ClientIRCOperator[R] == true) {
			K += 1;
		}

		R += 1;
	}

	// Services.
	K += 1;

	return k;
}

int MsgNotEnoughParameters(char* Cmd,int ClientNR) {
	char MySendSTR[500];

	strcpy(MySendSTR,ServerSubject(" 461 "));
	strcat(MySendSTR,GetNick(ClientNR));
	strcat(MySendSTR," ");
	strcat(MySendSTR,Cmd);
	strcat(MySendSTR," :Not enough parameters");
	VSend(MySendSTR,ClientNR);

	return;
}

// If user isn't registered, send a notice.
bool Reg(int ClientNR) {
	char MySendSTR[300];
	strcpy(MySendSTR,"");

	if(ClientAuthed[ClientNR] == false) {
		sprintf(&MySendSTR[0],"%s %s :Please register first",ServerSubject(" 451"),GetNick(ClientNR));
		VSend(MySendSTR,ClientNR);
		return false;
	} else {
		return true;
	}
}

int ProcessPart(char* Target,char* Reason,int ClientID) {
	char LCLTarget[200];
	strncpy(LCLTarget,Target,199);
	LCLTarget[199] = 0;
	MakeValidChannelName(MyStringLe2);
	char MySendSTR[201];
	char MySendSTR2[500];
	strcpy(MySendSTR2,"\0");
	strcpy(MySendSTR,"\0");
	strncpy(MySendSTR,Reason,200);

	if(strlen(Reason) >= 200) {
		MySendSTR[200] = 0;
	}

	if(OnlySpaces(Target) == true) {
		return;
	}

	int R;

	if(FChannelExists(LCLTarget) == false) {
		sprintf(&MySendSTR2[0],"%s %s %s :No such channel",ServerSubject(" 403"),GetNick(ClientID),LCLTarget);
		VSend(MySendSTR2,ClientID);

		return;
	}

	R = ChannelID(LCLTarget);

	if(UserIsInChannel(ClientID,R) == false) {
		sprintf(&MySendSTR2[0],"%s %s %s :You're not on that channel",ServerSubject(" 442"),GetNick(ClientID),ChannelName[R]);
		VSend(MySendSTR2,ClientId);

		return;
	}

	sprintf(&MySendSTR2[0],":%s!%s@%s PART %s :%s",GetNick(ClientID),ClientUserID[ClientID],ClientHost[ClientID],ChannelName[R],MySendSTR);

	int K;

	SendToAllUsersInChannel(R,MySendSTR2,-1);

	K = 0;

	while(K < MAXCHANSPERUSER) {
		if(ClientInChannel[ClientID][K] == R) {
			ClientInChannel[ClientID][K] = -1;
		}

		K += 1;
	}

	int J;
	J = 0;
	int Z;
	Z = 0;

	while(J < MAXUSERS) {
		if(ClientExists[J] == true && ClientPleaseRemove[J] == false) {
			K = 0;

			while(K < MAXCHANSPERUSER) {
				if(ClientInChannel[J][K] == R) {
					Z = 1;

					break;
				}

				K += 1;
			}
		}
		J += 1;
	}

	if (Z <= 0 && ChannelModeRegistered[R] == false) {
		ChannelExists[R] = false;
	}
}